/********************************************************************************
 * Project Name		[JavaEE_Web]
 * File Name     	[ResourcesCacheFilter.java]
 * Creation Date 	[2015-01-01]
 * 
 * Copyright© ge.y.yang@gmail.com All Rights Reserved
 * 
 * Work hard, play harder, think big and keep fit
 ********************************************************************************/
package filter.cases;

import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.io.OutputStreamWriter;
import java.io.PrintWriter;
import java.util.HashMap;
import java.util.Map;

import javax.servlet.FilterChain;
import javax.servlet.ServletException;
import javax.servlet.ServletOutputStream;
import javax.servlet.annotation.WebFilter;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import javax.servlet.http.HttpServletResponseWrapper;

import filter.HttpFilter;

/**
 * 缓存数据到内存<br/>
 * 对于页面中很少更新的数据, 例如商品分类, 为避免每次都要从数据库查询分类数据, 因此可把分类数据缓存在内存或文件中, 以此来减轻数据库压力,
 * 提高系统响应速度<br/>
 * 
 * @author 不落的太阳(Sean Yang aka ShortPeace)
 * @version 1.0
 * @since jdk 1.8
 * 
 */

@WebFilter(filterName = "ResourcesCacheFilter", urlPatterns = "*.jsp")
public class ResourcesCacheFilter extends HttpFilter {

	// 缓存容器
	private Map<String, byte[]> cache = new HashMap<>();

	@Override
	public void doFilter(HttpServletRequest request, HttpServletResponse response, FilterChain filterChain)
			throws IOException, ServletException {
		// 1. 得到用户请求的uri
		String uri = request.getRequestURI();
		// 2. 查找缓存中有没有uri对应的response数据
		byte[] responseData = cache.get(uri);
		// 3. 如果缓存中有, 直接取缓存的response数据打给浏览器, 程序返回
		if (responseData != null) {
			// 根据字节数组和指定的字符编码构建字符串
			String uriString = new String(responseData, response.getCharacterEncoding());
			System.out.println(uriString);
			response.getOutputStream().write(responseData);
			return;
		}
		// 4. 如果缓存中没有数据, 让目标资源执行, 并捕获目标资源的输出
		CachedResponse cachedResponse = new CachedResponse(response);
		filterChain.doFilter(request, cachedResponse);
		// 获取缓冲流中的内容的字节数组
		responseData = cachedResponse.getBuffer();
		// 5. 把response数据以用户请求的uri为关键字保存到缓存中
		cache.put(uri, responseData);
		// 6. 把数据传给浏览器
		response.getOutputStream().write(responseData);
	}
}

/**
 * 
 * @author 不落的太阳(Sean Yang aka ShortPeace)
 * @version 1.0
 * @since jdk 1.8
 *
 */
class CachedResponse extends HttpServletResponseWrapper {

	// 捕获输出的缓存
	private ByteArrayOutputStream outputStream = new ByteArrayOutputStream();
	private PrintWriter writer;
	private HttpServletResponse response;

	public CachedResponse(HttpServletResponse response) {
		super(response);
		this.response = response;
	}

	@Override
	public ServletOutputStream getOutputStream() throws IOException {
		return new BufferedServletOutputStream(outputStream);
	}

	@Override
	public PrintWriter getWriter() throws IOException {
		writer = new PrintWriter(new OutputStreamWriter(outputStream, this.response.getCharacterEncoding()));
		return writer;
	}

	public byte[] getBuffer() {
		try {
			if (writer != null) {
				writer.close();
			}
			return outputStream.toByteArray();
		} catch (Exception e) {
			throw new RuntimeException(e);
		}
	}
}
